package generate

import (
	"fmt"
	"regexp"
	"strings"
	"text/template"
)

func genQuote() {
	fnFuncs, onFuncs := getFuncsQuote()
	writeTmpl("quote.h.tpl", "../c/quote.h", map[string]any{"On": onFuncs, "Fn": fnFuncs}, template.FuncMap{
		"trim": func(s string) string {
			return strings.TrimLeft(s, "*")
		},
	})
	writeTmpl("quote.cpp.tpl", "../c/quote.cpp", map[string]any{"On": onFuncs, "Fn": fnFuncs}, template.FuncMap{
		"trim": func(s string) string {
			return strings.TrimLeft(s, "*")
		},
	})

	// golang
	writeTmpl("quote_lnx.go.tpl", "../go/quote/quote_lnx.go", map[string]any{"On": onFuncs, "Fn": fnFuncs}, funcMapTradeFnQuote, funcMapTradeOnQuote)
}

// 调用函数,参数类型转换
var funcMapTradeFnQuote = template.FuncMap{
	// 去掉变量前的 *
	"trim": func(s string) string { return strings.Trim(s, "*") },
	// 在 trade_lnx.go 中的 C 头使用
	// C++的自定义类型,还原为 C++ 原始类型
	// 特别处理 ClientOrderNo -> char *, 正常处理会变成 char**
	"CHeaderBaseType": func(typ, name string) string {
		typ = strings.ReplaceAll(typ, "const ", "")
		if strings.HasPrefix(typ, "TapAPI") || strings.HasPrefix(typ, "const TapAPI") { // struct
			return "struct " + typ
		}
		if strings.HasPrefix(typ, "TAPISTR_") || strings.HasPrefix(typ, "TAPSTR_") {
			return "char *"
		}
		switch typ {
		case "ITapQuoteAPINotify": // spi
			return "void "
		case "TAPIRightIDType", "TAPIINT32":
			return "int"
		case "TAPIUINT32":
			return "unsigned int"
		case "TAPICHAR", "const TAPICHAR", "TAPIYNFLAG":
			return "char"
		case "TAPIUINT16":
			return "unsigned short"
		case "TAPIDATE":
			return "char *"
		default:
			fmt.Println(typ)
			return typ
		}
	},
	// go 请求函数参数
	// 转换为 go 的类型
	"C2Go": func(typ, name string) string {
		typ = strings.ReplaceAll(typ, "ITapTrade::", "") // On 函数类型中多出的前缀
		typ = strings.ReplaceAll(typ, "const", "")
		typ = strings.TrimSpace(typ)
		switch typ {
		case "ITapQuoteAPINotify": // spi
			return strings.Trim(name, "*") + " unsafe.Pointer"
		case "TAPICHAR": // char* -> string
			return strings.Trim(name, "*") + " string"
		}
		// *TAPISTR_50
		if strings.Contains(name, "*") {
			if !strings.Contains(typ, "TAPISTR_") { // 双重指针,只传递一层, 可能有问题!!!
				typ = "*" + typ
			}
			name = strings.Trim(name, "*")
		}
		// 重命名的 struct
		if strings.Contains(typ, "*") {
			if reqTpy, ok := Rsp2ReqMv[strings.Trim(typ, "*")]; ok {
				typ = "*" + reqTpy
			}
		}
		return name + " " + typ
	},
	// go 请求函数中调用 C 函数, 参数需转为 C 类型, 作为 C 函数的参数
	// TAPIUINT32 => C.int
	"Go2C": func(typ, name string) string {
		typ = strings.ReplaceAll(typ, "const ", "")
		typ = strings.TrimSpace(typ)
		name = strings.Trim(name, "*")
		if strings.HasPrefix(typ, "TapAPI") {
			// 重命名的 struct
			if reqTpy, ok := Rsp2ReqMv[typ]; ok {
				typ = reqTpy
			}
			return fmt.Sprintf("(*C.struct_%s)(unsafe.Pointer(%s))", typ, name)
		}
		// TAPISTR_10 -> [11]byte
		if strings.HasPrefix(typ, "TAPISTR_") || strings.HasPrefix(typ, "TAPSTR_") {
			// 转换后的 & 会变成 &amp;
			s := fmt.Sprintf("(*C.char)(unsafe.Pointer(&%s[0]))", name)
			return s
		}
		switch typ {
		case "TAPICHAR":
			return fmt.Sprintf("C.CString(%s)", name)
		case "TAPIUINT16":
			return fmt.Sprintf("C.ushort(%s)", name)
		case "TAPIUINT32":
			return fmt.Sprintf("(*C.uint)(unsafe.Pointer(%s))", name)
		case "TAPIRightIDType": // int
			return fmt.Sprintf("C.int(%s)", name)
		}
		fmt.Println(typ, " ", name)
		return name
	},
}

// 响应函数定义, 参数类型转换
var funcMapTradeOnQuote = template.FuncMap{
	// 响应函数变量的定义
	// OnConnected func(hsotAddr string)
	"DefineVar": func(typ, name string) string {
		typ = strings.ReplaceAll(typ, "ITapTrade::", "")
		typ = strings.ReplaceAll(typ, "const", "")
		typ = strings.TrimSpace(typ)
		if strings.Contains(typ, "TAPISTR_") {
			typ = "string"
		} else if strings.Contains(name, "*") { // name 中有* 指针
			name = strings.Trim(name, "*")
			if reqTpy, ok := Rsp2ReqMv[typ]; ok {
				typ = reqTpy
			}
			typ = "*" + typ
		} else {
			switch typ {
			case "TAPIDATE": // 原定义为 [n]byte
				typ = "string"
			}
		}
		return name + " " + typ
	},
	// 响应函数声明中的参数, 由 c 转换为 cgo 类型
	"CCB": func(typ, name string) string {
		typ = strings.ReplaceAll(typ, "ITapTrade::", "") // On 函数类型中多出的前缀
		typ = strings.ReplaceAll(typ, "const ", "")
		// 回调函数里的 struct 参数
		if strings.Contains(typ, "TapAPI") {
			// 重命名的 struct
			if reqTpy, ok := Rsp2ReqMv[typ]; ok {
				typ = reqTpy
			}
			typ = fmt.Sprintf("*C.struct_%s", strings.TrimSpace(strings.Trim(typ, "*")))
		} else if strings.Contains(typ, "TAPISTR_") {
			typ = "*C.char"
		} else {
			switch typ {
			case "TAPIYNFLAG":
				typ = "C.char"
			case "TAPIINT32":
				typ = "C.int"
			case "TAPIUINT32":
				typ = "C.uint"
			case "bool":
				typ = "C._BOOL"
			case "int":
				typ = "C.int"
			case "TAPIDATE":
				typ = "*C.char"
			}
		}
		name = strings.Trim(name, "*")
		return name + " " + typ
	},
	// C的函数参数转为go类型
	"cgo": func(typ, name string) string {
		typ = strings.ReplaceAll(typ, "ITapTrade::", "")
		typ = strings.ReplaceAll(typ, "const", "")
		typ = strings.TrimSpace(typ)
		if strings.Contains(typ, "TAPISTR_") {
			return fmt.Sprintf("GBK(%s)", name)
		} else if strings.Contains(name, "*") { // name 中有* 指针
			// (*TapAPITradeLoginRspInfo)(unsafe.Pointer(loginRspInfo))
			name = strings.Trim(name, "*")
			// 类型替代
			if reqTpy, ok := Rsp2ReqMv[typ]; ok {
				typ = reqTpy
			}
			return fmt.Sprintf("(*%s)(unsafe.Pointer(%s))", typ, name)
		} else {
			switch typ {
			case "TAPIDATE":
				return fmt.Sprintf("GBK(%s)", name)
			}
		}
		return fmt.Sprintf("%s(%s)", typ, name)
	},
}

// getFuncsQuote 获取行情调用/响应函数
func getFuncsQuote() (fn []Func, on []Func) {
	str := readFile("TapQuoteAPI.h")
	// virtual void TAP_CDECL OnRtnContactInfo(ITapTrade::TAPIINT32 errorCode, ITapTrade::TAPIYNFLAG isLast, const ITapTrade::TAPISTR_40 ContactInfo) = 0;
	re := regexp.MustCompile(`virtual.*TAP_CDECL (\w+)\(([^)]*)`)
	matchs := re.FindAllStringSubmatch(str, -1)
	onFuncs := make([]Func, 0)
	fnFuncs := make([]Func, 0)
	// 取响应函数列表
	for _, m := range matchs {
		funcName := m[1]
		params := m[2]
		fn := Func{
			FuncName: funcName,
		}
		// virtual void TAP_CDECL OnRtnCombinePosition(const ITapTrade::TapAPICombinePositionInfo *info) {};
		// int days 为何会被漏掉? 在`?:ITapTrade|const ITapTrade`中增加 最后一个字段'|in'
		// virtual void TAP_CDECL OnExpriationDate(ITapTrade::TAPIDATE date, int days) = 0;
		// virtual void TAP_CDECL OnRspRequestVertificateCode(ITapTrade::TAPIUINT32 sessionID, ITapTrade::TAPIINT32 errorCode, const TapAPIRequestVertificateCodeRsp *rsp) = 0;
		// virtual void TAP_CDECL OnRspQryPositionSummary(TAPIUINT32 sessionID, TAPIINT32 errorCode, TAPIYNFLAG isLast, const TapAPIPositionSummary *info) = 0;
		re = regexp.MustCompile(`((?:ITapTrade|const ITapTrade|in|const TapAPI|TAP)[\w:]+)\s+(\*?\w+)`)
		fields := re.FindAllStringSubmatch(params, -1)
		for _, p := range fields {
			fn.Params = append(fn.Params, struct {
				Type string
				Name string
			}{
				Type: p[1],
				Name: p[2],
			})
		}
		if strings.HasPrefix(funcName, "On") {
			onFuncs = append(onFuncs, fn)
		}
	}

	fmt.Println("响应函数数量: ", len(onFuncs))

	// 取请求函数列表
	for _, m := range matchs {
		funcName := m[1]
		// 只处理 非 On 开头
		if strings.HasPrefix(funcName, "On") {
			continue
		}
		params := m[2]
		fn := Func{
			FuncName: funcName,
		}
		// virtual  ITapTrade::TAPIINT32 TAP_CDECL VerificateUnFreezeInfo(TAPIUINT32 *sessionID, const TapAPIVerifyIdentityReq *qryReq) = 0;
		// virtual ITapTrade::TAPIINT32 TAP_CDECL QryPositionSummary(ITapTrade::TAPIUINT32 *sessionID, const ITapTrade::TapAPIPositionQryReq *qryReq) = 0;
		re = regexp.MustCompile(`((?:T|const T|I|const I)[\w:]+)\s+(\*?\s?\w+)`)
		fields := re.FindAllStringSubmatch(params, -1)
		for _, p := range fields {
			fn.Params = append(fn.Params, struct {
				Type string
				Name string
			}{
				// 去掉 参数中的 namespace
				Type: strings.ReplaceAll(p[1], "ITapTrade::", ""),
				Name: p[2],
			})
		}
		fnFuncs = append(fnFuncs, fn)
	}

	fmt.Println("请求函数数量: ", len(fnFuncs))
	return fnFuncs, onFuncs
}

func genStructCgoQuote() {
	structs := getStructsCQuote()
	writeTmpl("struct.cgo.tpl", "../go/quote/struct_cgo.h", structs, template.FuncMap{
		"cgo": func(typ, name string) string {
			if strings.HasPrefix(typ, "TAPISTR_") {
				return fmt.Sprintf("char %s[%s]", name, typ[8:])
			} else if (strings.HasPrefix(typ, "TapAPI") || strings.HasPrefix(typ, "TAPI")) && strings.HasSuffix(typ, "Type") { // TapAPIApplyStatusType TAPIHedgeFlagType
				typ = "char"
			} else {
				switch typ {
				case "TapAPICommodity", "TapAPINewOrder", "TapAPIContract": // 本来就是 struct
					typ = "struct " + typ
				case "TAPICHAR", "TAPIYNFLAG", "TAPILOGLEVEL", "TAPIAccountState", "TAPIORDERACT":
					typ = "char"
				case "TAPIUINT32":
					typ = "unsigned int"
				case "TAPIINT32":
					typ = "int"
				case "TAPIQVOLUME": // uint64
					typ = "unsigned long long"
				case "TAPIQDIFF": // int64
					typ = "long long"
				case "TAPIREAL64", "TAPIQPRICE":
					typ = "double"
				case "TAPIDTSTAMP":
					return fmt.Sprintf("char %s[24]", name)
				case "TAPIAUTHCODE":
					return fmt.Sprintf("char %s[513]", name)
				case "TAPIMACTYPE":
					return fmt.Sprintf("char %s[13]", name)
				case "TAPIDATE":
					return fmt.Sprintf("char %s[11]", name)
				case "TAPIDATETIME":
					return fmt.Sprintf("char %s[20]", name)
				case "TAPICommodityType":
					typ = "char"
				default:
					fmt.Println(typ)
				}
			}
			return typ + " " + name
		},
	})
}

func genStructGoQuote() {
	structs := getStructsCQuote()
	writeTmpl("struct_quote.go.tpl", "../go/quote/structs.go", structs)
}

// getStructsC 获取 C 的 struct 定义
func getStructsCQuote() []Struct {
	// 读取文件内容
	str := readFile("TapAPICommDef.h", "TapQuoteAPIDataType.h")

	re := regexp.MustCompile(`struct\s*(\w*)\s*{([^}]*)}`) // 分成struct的注释,名称,字段两部分
	matchs := re.FindAllStringSubmatch(string(str), -1)

	structs := make([]Struct, 0)
	for _, m := range matchs {
		s := Struct{
			Name: m[1],
		}
		// 转换字段
		reField := regexp.MustCompile(`(\w+)\s+([^;]+);\s+///(.*)`)
		for _, f := range reField.FindAllStringSubmatch(m[2], -1) {
			s.Fields = append(s.Fields, struct {
				Name    string
				Type    string
				Comment string
			}{
				Name:    f[2],
				Type:    f[1],
				Comment: f[3],
			})
		}
		structs = append(structs, s)
	}
	fmt.Println("struct 数量: ", len(structs))
	return structs
}

// genDataTypeGo 生成 go 的数据类型
func genDataTypeGoQuote() {
	dataTypes := getDataTypeCQuote()
	// 模板生成(New后的名字要用完整的文件名)
	writeTmpl("datatype_quote.go.tpl", "../go/quote/datatype.go", dataTypes, template.FuncMap{
		"typeTrans": func(src string) string {
			switch src {
			case "char":
				return "string"
			case "int":
				return "int"
			case "long", "long long":
				return "int64"
			case "double":
				return "float64"
			case "unsigned int":
				return "uint"
			case "unsigned long", "unsigned long long": // TAPIUINT64
				return "uint64"
			case "unsigned short":
				return "uint16"
			case "unsigned char":
				return "uint8"
			}
			return src
		},
	})
}

// getDataTypeC 获取 C 中数据类型的定义
func getDataTypeCQuote() []DataType {
	// 读取文件内容
	str := readFile("TapAPICommDef.h", "TapQuoteAPIDataType.h")

	/*//! 看涨看跌标示
	  typedef TAPICHAR			TAPICallOrPutFlagType;*/
	// => type TAPICallOrPutFlagType byte
	//! 长度为10的字符串
	// typedef char	TAPISTR_10[11];
	// => type TAPISTR_10 [11]byte
	re := regexp.MustCompile(`//!?\s*(.*)\n\s?typedef\s+(\w+\s?\w+)\s+([\w[]+)`)
	defines := re.FindAllStringSubmatch(str, -1)

	/*    //! 买权
	const TAPICallOrPutFlagType		TAPI_CALLPUT_FLAG_CALL				= 'C';*/
	// const TAPI_CALLPUT_FLAG_CALL TAPICallOrPutFlagType = 'C'
	reConst := regexp.MustCompile(`//!\s+(.*)\n\s?const\s+(\w+)\s+(\w+)\s+=\s?\'(\w)\'`)
	consts := reConst.FindAllStringSubmatch(str, -1)

	dataTypes := make([]DataType, 0)
	for _, def := range defines {
		// typedef char	TAPISTR_10[11];
		comment := def[1]
		srcType := def[2]                    // c++ 类型
		typeName := def[3]                   // TAPISTR_10[11 ** 没有右括号
		if strings.Contains(typeName, "[") { // char[nn]
			srcType = fmt.Sprintf("[%s]byte", strings.Split(typeName, "[")[1])
			typeName = strings.Split(typeName, "[")[0]
		}
		dt := DataType{
			CType:    srcType,
			TypeName: typeName,
			Comment:  comment,
		}
		for _, c := range consts {
			comment := c[1]
			constType := c[2]
			constName := c[3]
			constValue := c[4]
			if strings.Contains(constType, typeName) {
				dt.Const = append(dt.Const, struct {
					TypeName string
					Name     string
					Value    string
					Comment  string
				}{
					TypeName: typeName,
					Name:     constName,
					Value:    constValue,
					Comment:  comment,
				})
			}
		}
		dataTypes = append(dataTypes, dt)
	}

	fmt.Println("数量: ", len(dataTypes))
	return dataTypes
}

// genTrade 生成 trade.h trade.cpp trade.go
func genTrade() {
	fnFuncs, onFuncs := getFuncs()
	// C++
	writeTmpl("trade.h.tpl", "../c/trade.h", map[string]any{"On": onFuncs, "Fn": fnFuncs}, template.FuncMap{
		"trim": func(s string) string {
			return strings.TrimLeft(s, "*")
		},
	})
	writeTmpl("trade.cpp.tpl", "../c/trade.cpp", map[string]any{"On": onFuncs, "Fn": fnFuncs}, template.FuncMap{
		"trim": func(s string) string {
			return strings.TrimLeft(s, "*")
		},
	})

	// golang
	writeTmpl("trade_lnx.go.tpl", "../go/lnx/trade_lnx.go", map[string]any{"On": onFuncs, "Fn": fnFuncs}, funcMapTradeFn, funcMapTradeOn)
}

type Func struct {
	FuncName string
	Params   []struct {
		Type string
		Name string
	}
}

func getFuncs() (fn []Func, on []Func) {
	str := readFile("iTapTradeAPI.h")
	// virtual void TAP_CDECL OnRtnContactInfo(ITapTrade::TAPIINT32 errorCode, ITapTrade::TAPIYNFLAG isLast, const ITapTrade::TAPISTR_40 ContactInfo) = 0;
	re := regexp.MustCompile(`virtual.*TAP_CDECL (\w+)\(([^)]*)`)
	matchs := re.FindAllStringSubmatch(str, -1)
	onFuncs := make([]Func, 0)
	fnFuncs := make([]Func, 0)
	// 取响应函数列表
	for _, m := range matchs {
		funcName := m[1]
		params := m[2]
		fn := Func{
			FuncName: funcName,
		}
		// virtual void TAP_CDECL OnRtnCombinePosition(const ITapTrade::TapAPICombinePositionInfo *info) {};
		// int days 为何会被漏掉? 在`?:ITapTrade|const ITapTrade`中增加 最后一个字段'|in'
		// virtual void TAP_CDECL OnExpriationDate(ITapTrade::TAPIDATE date, int days) = 0;
		// virtual void TAP_CDECL OnRspRequestVertificateCode(ITapTrade::TAPIUINT32 sessionID, ITapTrade::TAPIINT32 errorCode, const TapAPIRequestVertificateCodeRsp *rsp) = 0;
		// virtual void TAP_CDECL OnRspQryPositionSummary(TAPIUINT32 sessionID, TAPIINT32 errorCode, TAPIYNFLAG isLast, const TapAPIPositionSummary *info) = 0;
		re = regexp.MustCompile(`((?:ITapTrade|const ITapTrade|in|const TapAPI|TAP)[\w:]+)\s+(\*?\w+)`)
		fields := re.FindAllStringSubmatch(params, -1)
		for _, p := range fields {
			if strings.HasPrefix(p[1], "const TapAPI") { // 在struct 前加 ITapTrade::
				p[1] = fmt.Sprintf("const ITapTrade::%s", strings.ReplaceAll(p[1], "const ", ""))
			} else if strings.HasPrefix(p[1], "TAP") { // 参数前加 ITapTrade
				p[1] = "ITapTrade::" + p[1]
			}
			fn.Params = append(fn.Params, struct {
				Type string
				Name string
			}{
				Type: p[1],
				Name: p[2],
			})
		}
		if strings.HasPrefix(funcName, "On") {
			onFuncs = append(onFuncs, fn)
		}
	}

	fmt.Println("响应函数数量: ", len(onFuncs))

	// 取请求函数列表
	for _, m := range matchs {
		funcName := m[1]
		// 只处理 非 On 开头
		if strings.HasPrefix(funcName, "On") {
			continue
		}
		params := m[2]
		fn := Func{
			FuncName: funcName,
		}
		// virtual  ITapTrade::TAPIINT32 TAP_CDECL VerificateUnFreezeInfo(TAPIUINT32 *sessionID, const TapAPIVerifyIdentityReq *qryReq) = 0;
		// virtual ITapTrade::TAPIINT32 TAP_CDECL QryPositionSummary(ITapTrade::TAPIUINT32 *sessionID, const ITapTrade::TapAPIPositionQryReq *qryReq) = 0;
		re = regexp.MustCompile(`((?:T|const T|I|const I)[\w:]+)\s+(\*?\s?\w+)`)
		fields := re.FindAllStringSubmatch(params, -1)
		for _, p := range fields {
			fn.Params = append(fn.Params, struct {
				Type string
				Name string
			}{
				// 去掉 参数中的 namespace
				Type: strings.ReplaceAll(p[1], "ITapTrade::", ""),
				Name: p[2],
			})
		}
		fnFuncs = append(fnFuncs, fn)
	}

	fmt.Println("请求函数数量: ", len(fnFuncs))
	return fnFuncs, onFuncs
}

// .h 文件中别名的 struct 转换为原始类型
var Rsp2ReqMv = map[string]string{
	"TapAPIFillLocalRemoveRsp":    "TapAPIFillLocalRemoveReq",
	"TapAPIFillLocalInputRsp":     "TapAPIFillLocalInputReq",
	"TapAPIOrderLocalTransferRsp": "TapAPIOrderLocalTransferReq",
	"TapAPIOrderLocalModifyRsp":   "TapAPIOrderLocalModifyReq",
	"TapAPIOrderLocalInputRsp":    "TapAPIOrderLocalInputReq",
	"TapAPIOrderMarketDeleteRsp":  "TapAPIOrderMarketDeleteReq",
	"TapAPIOrderMarketInsertRsp":  "TapAPIOrderMarketInsertReq",
	"TapAPIHisOrderProcessQryRsp": "TapAPIHisOrderProcessQryReq",
	"TapAPIOrderActivateReq":      "TapAPIOrderCancelReq",
	"TapAPIOrderDeactivateReq":    "TapAPIOrderCancelReq",
	"TapAPIOrderDeleteReq":        "TapAPIOrderCancelReq",
}

// 调用函数,参数类型转换
var funcMapTradeFn = template.FuncMap{
	// 去掉变量前的 *
	"trim": func(s string) string { return strings.Trim(s, "*") },
	// 在 trade_lnx.go 中的 C 头使用
	// C++的自定义类型,还原为 C++ 原始类型
	// 特别处理 ClientOrderNo -> char *, 正常处理会变成 char**
	"CHeaderBaseType": func(typ, name string) string {
		typ = strings.ReplaceAll(typ, "ITapTrade::", "") // On 函数类型中多出的前缀
		typ = strings.ReplaceAll(typ, "const ", "")
		if strings.HasPrefix(typ, "TapAPI") || strings.HasPrefix(typ, "const TapAPI") { // struct
			// 重命名的 struct
			if reqTpy, ok := Rsp2ReqMv[typ]; ok {
				typ = reqTpy
			}
			return "struct " + typ
		}
		if strings.HasPrefix(typ, "TAPISTR_") || strings.HasPrefix(typ, "TAPSTR_") {
			// 特别处理, 原定义为 char**
			if strings.Contains(name, "ClientOrderNo") || strings.Contains(name, "ClientBuyOrderNo") || strings.Contains(name, "ClientSellOrderNo") || strings.Contains(name, "clientorderno") {
				return "char"
			}
			return "char *"
		}
		switch typ {
		case "ITapTradeAPINotify", "ITapQuoteAPINotify": // spi
			return "void "
		case "TAPIRightIDType", "TAPIINT32":
			return "int"
		case "TAPIUINT32":
			return "unsigned int"
		case "TAPICHAR", "const TAPICHAR", "TAPIYNFLAG":
			return "char"
		case "TAPIUINT16":
			return "unsigned short"
		case "TAPIDATE":
			return "char *"
		default:
			fmt.Println(typ)
			return typ
		}
	},
	// go 请求函数参数
	// 转换为 go 的类型
	"C2Go": func(typ, name string) string {
		typ = strings.ReplaceAll(typ, "ITapTrade::", "") // On 函数类型中多出的前缀
		typ = strings.ReplaceAll(typ, "const", "")
		typ = strings.TrimSpace(typ)
		switch typ {
		case "ITapTradeAPINotify": // spi
			return strings.Trim(name, "*") + " unsafe.Pointer"
		case "TAPICHAR": // char* -> string
			return strings.Trim(name, "*") + " string"
		}
		// *TAPISTR_50
		if strings.Contains(name, "*") {
			if !strings.Contains(typ, "TAPISTR_") { // 双重指针,只传递一层, 可能有问题!!!
				typ = "*" + typ
			}
			name = strings.Trim(name, "*")
		}
		// 重命名的 struct
		if strings.Contains(typ, "*") {
			if reqTpy, ok := Rsp2ReqMv[strings.Trim(typ, "*")]; ok {
				typ = "*" + reqTpy
			}
		}
		return name + " " + typ
	},
	// go 请求函数中调用 C 函数, 参数需转为 C 类型, 作为 C 函数的参数
	// TAPIUINT32 => C.int
	"Go2C": func(typ, name string) string {
		typ = strings.ReplaceAll(typ, "const ", "")
		typ = strings.TrimSpace(typ)
		name = strings.Trim(name, "*")
		if strings.HasPrefix(typ, "TapAPI") {
			// 重命名的 struct
			if reqTpy, ok := Rsp2ReqMv[typ]; ok {
				typ = reqTpy
			}
			return fmt.Sprintf("(*C.struct_%s)(unsafe.Pointer(%s))", typ, name)
		}
		// TAPISTR_10 -> [11]byte
		if strings.HasPrefix(typ, "TAPISTR_") || strings.HasPrefix(typ, "TAPSTR_") {
			// 转换后的 & 会变成 &amp;
			s := fmt.Sprintf("(*C.char)(unsafe.Pointer(&%s[0]))", name)
			return s
		}
		switch typ {
		case "TAPICHAR":
			return fmt.Sprintf("C.CString(%s)", name)
		case "TAPIUINT16":
			return fmt.Sprintf("C.ushort(%s)", name)
		case "TAPIUINT32":
			return fmt.Sprintf("(*C.uint)(unsafe.Pointer(%s))", name)
		case "TAPIRightIDType": // int
			return fmt.Sprintf("C.int(%s)", name)
		}
		fmt.Println(typ, " ", name)
		return name
	},
}

// 响应函数定义, 参数类型转换
var funcMapTradeOn = template.FuncMap{
	// 响应函数变量的定义
	// OnConnected func(hsotAddr string)
	"DefineVar": func(typ, name string) string {
		typ = strings.ReplaceAll(typ, "ITapTrade::", "")
		typ = strings.ReplaceAll(typ, "const", "")
		typ = strings.TrimSpace(typ)
		if strings.Contains(typ, "TAPISTR_") {
			typ = "string"
		} else if strings.Contains(name, "*") { // name 中有* 指针
			name = strings.Trim(name, "*")
			if reqTpy, ok := Rsp2ReqMv[typ]; ok {
				typ = reqTpy
			}
			typ = "*" + typ
		} else {
			switch typ {
			case "TAPIDATE": // 原定义为 [n]byte
				typ = "string"
			}
		}
		return name + " " + typ
	},
	// 响应函数声明中的参数, 由 c 转换为 cgo 类型
	"CCB": func(typ, name string) string {
		typ = strings.ReplaceAll(typ, "ITapTrade::", "") // On 函数类型中多出的前缀
		typ = strings.ReplaceAll(typ, "const ", "")
		// 回调函数里的 struct 参数
		if strings.Contains(typ, "TapAPI") {
			// 重命名的 struct
			if reqTpy, ok := Rsp2ReqMv[typ]; ok {
				typ = reqTpy
			}
			typ = fmt.Sprintf("*C.struct_%s", strings.TrimSpace(strings.Trim(typ, "*")))
		} else if strings.Contains(typ, "TAPISTR_") {
			typ = "*C.char"
		} else {
			switch typ {
			case "TAPIYNFLAG":
				typ = "C.char"
			case "TAPIINT32":
				typ = "C.int"
			case "TAPIUINT32":
				typ = "C.uint"
			case "bool":
				typ = "C._BOOL"
			case "int":
				typ = "C.int"
			case "TAPIDATE":
				typ = "*C.char"
			}
		}
		name = strings.Trim(name, "*")
		return name + " " + typ
	},
	// C的函数参数转为go类型
	"cgo": func(typ, name string) string {
		typ = strings.ReplaceAll(typ, "ITapTrade::", "")
		typ = strings.ReplaceAll(typ, "const", "")
		typ = strings.TrimSpace(typ)
		if strings.Contains(typ, "TAPISTR_") {
			return fmt.Sprintf("GBK(%s)", name)
		} else if strings.Contains(name, "*") { // name 中有* 指针
			// (*TapAPITradeLoginRspInfo)(unsafe.Pointer(loginRspInfo))
			name = strings.Trim(name, "*")
			// 类型替代
			if reqTpy, ok := Rsp2ReqMv[typ]; ok {
				typ = reqTpy
			}
			return fmt.Sprintf("(*%s)(unsafe.Pointer(%s))", typ, name)
		} else {
			switch typ {
			case "TAPIDATE":
				return fmt.Sprintf("GBK(%s)", name)
			}
		}
		return fmt.Sprintf("%s(%s)", typ, name)
	},
}

// genStructCgoTrade 生成用于 Cgo 的struct(struct中的字段均用C的基础类型)
func genStructCgoTrade() {
	structs := getStructsCTrade()
	writeTmpl("struct.cgo.tpl", "../trade/struct_cgo.h", structs, template.FuncMap{
		"cgo": func(typ, name string) string {
			if strings.HasPrefix(typ, "TAPISTR_") {
				return fmt.Sprintf("char %s[%s]", name, typ[8:])
			} else if (strings.HasPrefix(typ, "TapAPI") || strings.HasPrefix(typ, "TAPI")) && strings.HasSuffix(typ, "Type") { // TapAPIApplyStatusType TAPIHedgeFlagType
				typ = "char"
			} else {
				switch typ {
				case "TapAPICommodity", "TapAPINewOrder", "TapAPIContract": // 本来就是 struct
					typ = "struct " + typ
				case "TAPICHAR", "TAPIYNFLAG", "TAPILOGLEVEL", "TAPIAccountState", "TAPIORDERACT":
					typ = "char"
				case "TAPIUINT32":
					typ = "unsigned int"
				case "TAPIINT32":
					typ = "int"
				case "TAPIQVOLUME": // uint64
					typ = "unsigned long long"
				case "TAPIQDIFF": // int64
					typ = "long long"
				case "TAPIREAL64", "TAPIQPRICE":
					typ = "double"
				case "TAPIDTSTAMP":
					return fmt.Sprintf("char %s[24]", name)
				case "TAPIAUTHCODE":
					return fmt.Sprintf("char %s[513]", name)
				case "TAPIMACTYPE":
					return fmt.Sprintf("char %s[13]", name)
				case "TAPIDATE":
					return fmt.Sprintf("char %s[11]", name)
				case "TAPIDATETIME":
					return fmt.Sprintf("char %s[20]", name)
				case "TAPICommodityType":
					typ = "char"
				default:
					fmt.Println(typ)
				}
			}
			return typ + " " + name
		},
	})
}

type Struct struct {
	Name   string
	Fields []struct {
		Name    string
		Type    string
		Comment string
	}
}

// genStructGoTrade 生成 struct golang
func genStructGoTrade() {
	structs := getStructsCTrade()
	// 模板生成(New后的名字要用完整的文件名)
	writeTmpl("struct.go.tpl", "../trade/structs.go", structs)
}

// getStructsCTrade 获取 C 的 struct 定义
func getStructsCTrade() []Struct {
	// 读取文件内容
	str := readFile("iTapAPICommDef.h", "iTapTradeAPIDataType.h")

	re := regexp.MustCompile(`struct\s*(\w*)\s*{([^}]*)}`) // 分成struct的注释,名称,字段两部分
	matchs := re.FindAllStringSubmatch(string(str), -1)

	structs := make([]Struct, 0)
	for _, m := range matchs {
		s := Struct{
			Name: m[1],
		}
		// 转换字段
		reField := regexp.MustCompile(`(\w+)\s+([^;]+);\s+/{0,3}(.*)`) // 左杠2个或没有的情况
		for _, f := range reField.FindAllStringSubmatch(m[2], -1) {
			s.Fields = append(s.Fields, struct {
				Name    string
				Type    string
				Comment string
			}{
				Name:    f[2],
				Type:    f[1],
				Comment: f[3],
			})
		}
		structs = append(structs, s)
	}
	fmt.Println("struct 数量: ", len(structs))
	return structs
}

type DataType struct {
	CType    string // C++ 类型
	TypeName string
	Comment  string
	Const    []struct {
		TypeName string
		Name     string
		Value    string
		Comment  string
	}
}

// genDataTypeGoTrade 生成 go 的数据类型
func genDataTypeGoTrade() {
	dataTypes := getDataTypeCTrade()
	// 模板生成(New后的名字要用完整的文件名)
	writeTmpl("datatype.go.tpl", "../trade/datatype.go", dataTypes, template.FuncMap{
		"typeTrans": func(src string) string {
			switch src {
			case "char":
				return "string"
			case "int":
				return "int"
			case "long", "long long":
				return "int64"
			case "double":
				return "float64"
			case "unsigned int":
				return "uint"
			case "unsigned long":
				return "uint64"
			case "unsigned short":
				return "uint16"
			case "unsigned char":
				return "uint8"
			}
			return src
		},
	})
}

// getDataTypeCTrade 获取 C 中数据类型的定义
func getDataTypeCTrade() []DataType {
	// 读取文件内容
	str := readFile("iTapAPICommDef.h", "iTapTradeAPIDataType.h")

	/*//! 看涨看跌标示
	  typedef TAPICHAR			TAPICallOrPutFlagType;*/
	// => type TAPICallOrPutFlagType byte
	//! 长度为10的字符串
	// typedef char	TAPISTR_10[11];
	// => type TAPISTR_10 [11]byte
	re := regexp.MustCompile(`//!?\s*(.*)\n\s+typedef\s+(\w+\s?\w+)\s+([\w[]+)`)
	defines := re.FindAllStringSubmatch(str, -1)

	/*    //! 买权
	const TAPICallOrPutFlagType		TAPI_CALLPUT_FLAG_CALL				= 'C';*/
	// const TAPI_CALLPUT_FLAG_CALL TAPICallOrPutFlagType = 'C'
	reConst := regexp.MustCompile(`//!\s+(.*)\n\s+const\s+(\w+)\s+(\w+)\s+=\s?\'(\w)\'`)
	consts := reConst.FindAllStringSubmatch(str, -1)

	dataTypes := make([]DataType, 0)
	for _, def := range defines {
		// typedef char	TAPISTR_10[11];
		comment := def[1]
		srcType := def[2]                    // c++ 类型
		typeName := def[3]                   // TAPISTR_10[11 ** 没有右括号
		if strings.Contains(typeName, "[") { // char[nn]
			srcType = fmt.Sprintf("[%s]byte", strings.Split(typeName, "[")[1])
			typeName = strings.Split(typeName, "[")[0]
		}
		dt := DataType{
			CType:    srcType,
			TypeName: typeName,
			Comment:  comment,
		}
		for _, c := range consts {
			comment := c[1]
			constType := c[2]
			constName := c[3]
			constValue := c[4]
			if strings.Contains(constType, typeName) {
				dt.Const = append(dt.Const, struct {
					TypeName string
					Name     string
					Value    string
					Comment  string
				}{
					TypeName: typeName,
					Name:     constName,
					Value:    constValue,
					Comment:  comment,
				})
			}
		}
		dataTypes = append(dataTypes, dt)
	}

	fmt.Println("数量: ", len(dataTypes))
	return dataTypes
}
